/* Copyright - Apache License 2.0
 * 
 * The project "kyou" is
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.kyou.data.dquery;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import net.kyou.data.SchemaItem;
import net.kyou.exception.KyouErr;
import net.kyou.exception.KyouException;

/**
 * DQuery是一种针对某个或某些报文元素的描述方式
 * 
 * @author NuclearG (<a href="mailto:nuclearg@163.com">nuclearg@163.com</a>)
 */
public class DQuery {
    private static final Map<String, String> mappings;
    static {
        Map<String, String> map = new HashMap<String, String>();
        map.put("#FIELD", "**[FIELD array!=true]");
        map.put("#FIELDINARRAY", "**[* FIELD array=true]");
        map.put("#FIELDARRAY", "**[FIELD array=true]");
        map.put("#STRU", "**[STRU array!=true]");
        map.put("#STRUINARRAY", "**[* STRU array=true]");
        map.put("#STRUARRAY", "**[STRU array=true]");

        mappings = Collections.unmodifiableMap(map);
    }

    /**
     * 实际执行处理的DQuery实例
     */
    private final DQuery impl;

    /**
     * 初始化一个DQuery实例
     * 
     * @param query
     *            dquery字符串
     */
    public DQuery(String query) {
        if (query == null || query.length() == 0)
            throw new KyouException(KyouErr.Schema.Query.NullDQuery, query);

        if (mappings.containsKey(query))
            query = mappings.get(query);

        DQuerySegment[] segments = this.parse(query);
        this.impl = this.analyse(query, segments);
    }

    /**
     * 供子类重载时使用的构造函数
     */
    DQuery() {
        this.impl = null;
    }

    /**
     * 判断某个报文元素是否符合当前DQuery实例的描述
     * 
     * @param path
     *            报文元素路径
     * @param schema
     *            报文元素的Schema
     * @return 该报文元素是否符合DQuery的描述
     */
    public boolean matches(String path, SchemaItem schema) {
        return this.impl.matches(path, schema);
    }

    /**
     * 工具函数 解析DQuery字符串，解析成一系列的DQuery段。
     */
    private DQuerySegment[] parse(String query) {
        // TODO 改成基于词法分析的dquery解析
        ArrayList<DQuerySegment> segments = new ArrayList<DQuerySegment>();
        for (String segment : query.split("\\."))
            segments.add(new DQuerySegment(segment));

        return segments.toArray(new DQuerySegment[0]);
    }

    /**
     * 工具函数 分析DQuery列表，根据这些列表推断出适合的DQueryImpl。
     */
    private DQuery analyse(String query, DQuerySegment[] segments) {
        /*
         * 判断依据： 如果所有段都没有约束条件，且下标不为WILDCHAR，且首段为ROOT，则这个query表示一个单纯的路径，由BasicDQuery处理。 其它情况作为ComplexDQuery处理。
         */
        boolean complex = false;
        for (DQuerySegment segment : segments)
            if (segment.restrictions.length != 0 || segment.indexes == null)
                complex = true;

        return complex ? new ComplexDQuery(segments) : new BasicDQuery(query);
    }
}
